var system = require('system');
var webpage = require('webpage');
var isLoading = false;
var currentRequestCount = 0;
var isSupportedAjax = true;

function doExit(code) {
    phantom.exit(code);
}

function toBool(arg, deft) {
    if (arg == null || arg === '' || isNaN(arg)) {
        return Boolean(deft);
    } else {
        return Boolean(arg);
    }
}

function toInt(arg, deft) {
    var v = parseInt(arg);
    if (isNaN(v)) {
        return parseInt(deft);
    } else {
        return v;
    }
}

function isEmpty(arg) {
    return arg == null || arg == '';
}

function sendResponse(resp) {
    system.stdout.writeLine('<--response start-->');
    system.stdout.writeLine(resp);
}

function sendCommonResponse(result, content) {
    sendResponse(JSON.stringify({'result': result, 'content': content}))
}

function sendLoadPageResponse(status, url, content) {
    sendResponse(JSON.stringify({'result': status, 'url': url, 'content': content}));
}

function getPageContent(page, param) {
    var contentType = param.contentType;
    if (contentType == 'image') {
        var imagePath = param.imagePath;
        if (isEmpty(imagePath)) {
            return null;
        }
        try {
            page.render(imagePath);
            return imagePath;
        } catch (err) {
            return '';
        }
    } else {
        return page.content;
    }
}

function createPage(param) {
    if (isEmpty(param.userAgent)) {
        param.userAgent = 'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:26.0) Gecko/20100101 Firefox/26.0';
    }
    var page = webpage.create();
    page.settings.javascriptEnabled = toBool(param.javascriptEnabled, true);
    page.settings.loadImages = toBool(param.loadImages, false);
    page.settings.localToRemoteUrlAccessEnabled = toBool(param.localToRemoteUrlAccessEnabled, true);
    page.settings.userAgent = param.userAgent;
    page.settings.userName = param.userName;
    page.settings.password = param.password;
    page.settings.XSSAuditingEnabled = toBool(param.XSSAuditingEnabled, false);
    page.settings.webSecurityEnabled = toBool(param.webSecurityEnabled, false);
    page.settings.resourceTimeout = toInt(param.resourceTimeout, 10000);
    var viewportSize = param.viewportSize;
    if (viewportSize != null) {
        page.viewportSize = viewportSize;
    }
    var clipRect = param.clipRect;
    if (clipRect != null) {
        page.clipRect = clipRect;
    }
    page.onResourceRequested = function (requestData, networkRequest) {
        currentRequestCount++;
    };
    page.onResourceReceived = function (response) {
        if (response.stage === 'end') {
            currentRequestCount--;
        }
    };
    page.onError = function (msg, trace) {
        if (msg != null && msg.indexOf('Cannot init XMLHttpRequest') >= 0) {
            isSupportedAjax = false;
        }
    };
    return page;
}

var tempTimeout = 0;
function waitForLoaded(page, param, endFunction) {
    if (!isSupportedAjax) {
        sendLoadPageResponse(true, page.url, getPageContent(page, param));
        page.close();
        isLoading = false;
    } else {
        var waiter = setTimeout(function () {
            tempTimeout -= 500;
            var flag = 0;
            if (!isEmpty(endFunction)) {
                try {
                    if (page.evaluate(new Function(endFunction))) {
                        flag = 1;
                    } else {
                        flag = 0;
                    }
                } catch (err) {
                    flag = -1;
                }
            } else if (currentRequestCount === 0) {
                flag = 1;
            } else {
                flag = 0;
            }
            if (flag === -1) {
                sendLoadPageResponse(false, page.url, 'invalid end function str');
                page.close();
                isLoading = false;
            } else if (flag === 0) {
                if (tempTimeout > 0) {
                    waitForLoaded(page, param, endFunction);
                } else {
                    sendLoadPageResponse(false, page.url, 'wait request timeout');
                    page.close();
                    isLoading = false;
                }
            } else {
                sendLoadPageResponse(true, page.url, getPageContent(page, param));
                page.close();
                isLoading = false;
            }
        }, 500);
    }
}

function loadPageByUrl(url, param) {
    if (isEmpty(url)) {
        return;
    }
    try {
        isLoading = true;
        var page = createPage(param);
        page.open(url, function (status) {
            if (status === 'success') {
                if (page.settings.javascriptEnabled) {
                    tempTimeout = toInt(param.waitTime, page.settings.resourceTimeout);
                    waitForLoaded(page, param, param.endFunction);
                } else {
                    sendLoadPageResponse(true, page.url, getPageContent(page, param));
                    page.close();
                    isLoading = false;
                }
            } else {
                sendLoadPageResponse(false, page.url, 'status: ' + status);
                page.close();
                isLoading = false;
            }
        });
    } catch (err) {
        sendLoadPageResponse(false, url, 'exception: ' + err.message);
    }
}

function loadPageByHtml(url, text, param) {
    if (isEmpty(text)) {
        return;
    }
    var page = createPage(param);
    try {
        isLoading = true;
        page.setContent(text, url);
        if (page.settings.javascriptEnabled) {
            tempTimeout = toInt(param.waitTime, page.settings.resourceTimeout);
            waitForLoaded(page, param, param.endFunction);
        } else {
            sendLoadPageResponse(true, url, getPageContent(page, param));
            isLoading = false;
            page.close();
        }
    } catch (err) {
        sendLoadPageResponse(false, url, 'exception: ' + err.message);
        isLoading = false;
        page.close();
    }
}

function loadPage(content) {
    var type = content.type;
    currentRequestCount = 0;
    isSupportedAjax = true;
    if ('url' === type) {
        return loadPageByUrl(content.url, content);
    } else if ('html' === type) {
        return loadPageByHtml(content.url, content.text, content);
    }
}

function modCookie(content) {
    var type = content.type;
    if ('enable' == type) {
        var isEnable = content.cookieEnable;
        if (!isEmpty(isEnable)) {
            phantom.cookiesEnabled = toBool(isEnable);
        }
        sendResponse(JSON.stringify({'result': true, 'cookieEnable': phantom.cookiesEnabled}));
        return;
    } else if ('get' === type) {
        sendResponse(JSON.stringify({'result': true, 'cookies': phantom.cookies}));
        return;
    }
    var result = false;
    if ('add' === type) {
        result = phantom.addCookie(content.cookie);
    } else if ('clear' === type) {
        phantom.clearCookies();
        result = true;
    } else if ('delete' === type) {
        result = phantom.deleteCookie(content.cookieName);
    }
    sendResponse(JSON.stringify({'result': result}));
}
var defaultEncoding = phantom.outputEncoding;
var mainInterval = setInterval(function () {
    if (!isLoading) {
        try {
            var content = system.stdin.readLine();
            if (isEmpty(content)) {
                doExit();
                return;
            }
            content = JSON.parse(content);
            var encoding = content.encoding;
            if (isEmpty(encoding)) {
                encoding = defaultEncoding;
            }
            try {
                phantom.outputEncoding = encoding;
            } catch (e) {
                phantom.outputEncoding = defaultEncoding;
            }
            var method = content.method;
            if ('exit' === method) {
                doExit();
            } else if ('loadPage' === method) {
                loadPage(content);
            } else if ('modCookie' === method) {
                modCookie(content);
            } else {
                sendCommonResponse(false, 'unsupported method: ' + method);
            }
        } catch (err) {
            sendCommonResponse(false, 'exception: ' + err.message);
        }
    }
}, 1);

